#include "p8x32a.h"
#include "p8x32a_rom.h"
#include "Sleeper.h"

#include <QApplication>

/*
 * Large portions of the execute() function below are copied from Dave Hein's
 * spinsim066, pasmsim.c file. There are differences now because of the time
 * keeping and single PC code changes. Still, Dave's work is appreciated and
 * deserves credit it this work. See P8x32a::execute(int cog, bool debug) below.
 */

P8x32a::P8x32a(Micro *parent) :
    Micro(parent), lastcog(0), printinst(false),
    brkKeyNum(0), breakOnCoginit(0)
{
    dropBox.setTitle(tr("Drop Box"));
    dropBox.setMinimumHeight(20);
    //dropBox.setStyleSheet("QGroupBox { background: white; }");
    dropBox.setAcceptDrops(true);

    layout.addWidget(&dropBox,0,0,2,17);
    for(int n = 0; n < P8x32a::PINCOUNT; n++) {
        PinType *pin  = new PinType();
        pin->setText(QString("%1").arg(n));
        pin->setChecked(false);
#if defined(Q_OS_WIN)
        pin->setMinimumWidth(40);
#else
        pin->setMinimumWidth(55);
#endif
        pins.append(pin);
        layout.addWidget(pin, 1-n/16+2, 16-n%16);
    }
    setLayout(&layout);

    //traceEdit.setReadOnly(true); // need clear trace for this to be useful.
    traceEdit.setWindowTitle("Simulator Trace");
    traceon = true;
    //connect(&traceEdit,SIGNAL(cursorPositionChanged()),this,SLOT(updateBackgroundColors())); // too slow!
    initialize();

    //printinst = true;
}

P8x32a::~P8x32a()
{
    brkHash.clear();
    for(int n = 0; n < P8x32a::PINCOUNT; n++) {
        PinType *pin  = pins.at(n);
        delete pin;
    }
}

void P8x32a::boot()
{
    if(running == false) {
        if(coginit((uint32*)&memory[interpAddr],4,0,0) > -1)
            running = true;
        emit setCogPC(0,0);
    }
}

void P8x32a::initialize()
{
    running = false;
    resethub();
    brkHash.clear();
    passBreak = false;
    traceEdit.setPlainText("");
    loopcount = 0;
    for(int n = 0; n < COGCOUNT; n++) {
        resetcog(n);
    }

    clearBreakpoints();

    emit clearHubMem();
    emit setCogPC(0,0); // start with COG 0
}

int P8x32a::load(const char *ptr, int size)
{
    initialize();

    if(size >= RAMSIZE) {
        qDebug() << "Program exceeds memory size";
        return 1;
    }
    if(size < 1) {
        qDebug() << "Program size < 1 ???";
        return 1;
    }
    copyShowHub(ptr, size);
    return 0;
}

void P8x32a::copyShowHub(const char *ptr, int size)
{
    int stackBase = 0;
    uchar *mptr = (uchar*)memory;

    int n = 0;
    for(; n < size; n++) {
        mptr[n] = ptr[n];
        if(n == 0xB)
            stackBase = mptr[n-1] | (mptr[n] << 8);
        if(!(n % 0x1000)) QApplication::processEvents();
    }
    for(;n < stackBase; n++) {
        mptr[n] = 0;
    }

    n = stackBase-8;
    mptr[n++] = 0xFF;
    mptr[n++] = 0xFF;
    mptr[n++] = 0xF9;
    mptr[n++] = 0xFF;
    mptr[n++] = 0xFF;
    mptr[n++] = 0xFF;
    mptr[n++] = 0xF9;
    mptr[n++] = 0xFF;

    emit showHubMem(mptr, stackBase);
}

void P8x32a::resethub()
{
    uchar *mptr = memory;
    lastcog = 0;
    interpAddr = 0xF000;

    // default clock speed is 12MHz ... spin over-writes this
    *(uint32*)(memory) = 12000000;

    for(int n = 0; n < COGCOUNT; n++) {
        cogrun[n] = false;
        locks[n] = false;
    }
    for(int n = 0; n < PINCOUNT; n++) {
        pindir[n] = 0;
        pinout[n] = 0;
        pins.at(n)->setStyleSheet("QCheckBox { background-color: white; }");
    }
    /*
    for(int n = 0; n < ROMSIZE; n++) {
        mptr[n+ROMSTART] = romdata[n];  // memory and regs should be longs
    }
    */
    for(int n = 0; n < interpreter_size; n++) {
        mptr[n+interpAddr] = interpreter_array[n];
        //qDebug("INTRP [%d/%04X] %02X", n+interpAddr, n+interpAddr, mptr[n+interpAddr]);
    }
}

void P8x32a::resetcog(int num)
{
    pc0[num]  = 0;
    pc1[num] = 0;

    for(int n = 0; n < COGSIZE; n++) {
        cogmem[num][n] = 0;
        cogrun[num] = false;
        cogstarted[num] = false;
        waitflag[num] = 0;
    }
    coginfo[num].codeList.clear();
    for(int n = 0; n < COGSIZE; n++) {
        coginfo[num].codeList.append(0);
        ina[num]  = 0;
        inb[num]  = 0;
        outa[num] = 0;
        outb[num] = 0;
        dira[num] = 0;
        dirb[num] = 0;
        frqa[num] = 0;
        frqb[num] = 0;
        phsa[num] = 0;
        phsb[num] = 0;
        vcfg[num] = 0;
        vscl[num] = 0;
    }

    emit clearCogMem(num);
}

int  P8x32a::coginit(uint32 *codep, int par, int num, int newcog = 1)
{
    pc0[num]  = 0;
    pc1[num] = 0;

    if(codep == 0) {
        return -1;
    }
    // if newcog allocate a cog, else force use of num
    if(newcog) {
        int n = 0;
        for(;n < COGCOUNT; n++) {
            if(!cogrun[n]) {
                break;
            }
        }
        if(n == COGCOUNT) {
            return -1;
        }
        num = n;
    }
    resetcog(num);
    coginfo[num].codeList.clear();
    for(int n = 0; n < COGCODESIZE; n++) {
        //if(n < 16) qDebug("reg[%d] %08X", n, codep[n]);
        cogmem[num][n] = codep[n];
        coginfo[num].codeList.append(cogmem[num][n]);
    }
    emit addCogInstructions(num,coginfo[num].codeList);
    cogmem[num][REG_PAR] = par;
    cogrun[num] = true;

    if(breakOnCoginit) {
        setBreakpoint(0, num);
    }
    return num;
}

uint32  P8x32a::getPins(int cog)
{
    ina[cog] = 0;
    for(int n = 0; n < P8x32a::PINCOUNT; n++) {
        if(pins.at(n)->isChecked())
            ina[cog] |= 1 << n;
    }
    return ina[cog];
}

void    P8x32a::setPins(int cog, uint32 val)
{
    uint outs = 0;
    for(int n = 0; n < P8x32a::COGCOUNT; n++) {
        if(n != cog)
            outs |= outa[n];
    }
    outa[cog] = val;
    //qDebug() << "OUTA COG" << cog << val;

    for(int n = 0; n < P8x32a::PINCOUNT; n++) {
        int mask = 1 << n;
        if(dira[cog] & mask) {
            if(val & mask) {
                pins.at(n)->setStyleSheet("QCheckBox { background-color: lime; }");
            }
            else if(!(outs & mask)) {
                pins.at(n)->setStyleSheet("QCheckBox { background-color: lightgray; }");
            }
        }
    }
}

void    P8x32a::setPinDir(int cog, uint32 val)
{
    uint outs = 0;
    for(int n = 0; n < P8x32a::COGCOUNT; n++) {
        if(n != cog)
            outs |= outa[n];
    }
    dira[cog] = val;
    //qDebug() << "DIRA COG" << cog << val;

    for(int n = 0; n < P8x32a::PINCOUNT; n++) {
        int mask = 1 << n;
        if(val & mask) {
            if(!(dira[cog] & mask)) {
                if(!(outs & mask)) {
                    pins.at(n)->setStyleSheet("QCheckBox { background-color: lightgray; }");
                }
            }
        }
        else {
            if(dira[cog] & mask) {
                pins.at(n)->setStyleSheet("QCheckBox { background-color: white; }");
            }
        }
    }
}

/*
 * I would do it like this, but Dave's code seems to work.
    int par = 0;
    for(int n = 0; n < 32; n++) {
        if(val & (1<<n)) par++;
    }
    return par & 1;
 */
int32 P8x32a::parity(uint32 val)
{
    val ^= val >> 16;
    val ^= val >> 8;
    val ^= val >> 4;
    val ^= val >> 2;
    val ^= val >> 1;
    return val & 1;
}

int32  P8x32a::abs(int32 val)
{
    return val < 0 ? -val : val;
}

void P8x32a::showTrace(bool visible)
{
    traceEdit.setMinimumSize(1000,300);
    traceEdit.setFont(QFont("Courier New",9));
    traceEdit.setVisible(visible);
}

void P8x32a::setBreakpoint(int r, int cog)
{
    brkHash[QString("%1.%2").arg(cog).arg(r)] = -1;
    qDebug() << "setBreakpoint" << QString("%1.%2").arg(cog).arg(r);
}

void P8x32a::clearBreakpoint(int r, int cog)
{
    brkHash[QString("%1.%2").arg(cog).arg(r)] = 0;
    qDebug() << "clrBreakpoint" << QString("%1.%2").arg(cog).arg(r);
}

void P8x32a::clearBreakpoints()
{
    int cog;
    bool ok;
    QStringList ls;
    QList<QString> keys = brkHash.keys();
    foreach(QString key, keys) {
        ls = key.split(".",QString::SkipEmptyParts);
        cog = ls[0].toInt(&ok); // cog is 0, pc row is 1
        if(ok) emit clearBreakpoints(cog);
        brkHash.remove(key);
    }
}

void P8x32a::showBreakpoints()
{
    int cog;
    int row;
    bool ok;
    QStringList ls;
    QList<QString> keys = brkHash.keys();
    if(keys.isEmpty())
        return;
    int keycnt = 0;
    foreach(QString key, keys) {
        if(brkHash[key] == 0)
            continue;
        qDebug() << "showBreakpoints 1" << key;
        keycnt++;
    }
    if(keycnt == 0)
        return;
    brkKeyNum %= keycnt;
    int n = 0;
    foreach(QString key, keys) {
        if(brkHash[key] == 0)
            continue;
        qDebug() << "showBreakpoints 2" << key;
        if(brkKeyNum == n++) {
            qDebug() << "showBreakpoints 3" << key;
            ls = key.split(".",QString::SkipEmptyParts);
            cog = ls[0].toInt(&ok); // cog is 0, pc row is 1
            if(ok) {
                row  = ls[1].toInt(&ok);
                if(ok) {
                    emit showBreakpoint(cog, row);
                }
                break;
            }
        }
    }
    brkKeyNum++;
}

void   P8x32a::newCoreBreak(bool enable)
{
    breakOnCoginit = enable;
}

void   P8x32a::updateState()
{
    copyShowHub((const char*)&memory[0], MEMSIZE);
    for(int num = 0; num < COGCOUNT; num++) {
        if(!cogrun[num])
            continue;
        coginfo[num].codeList.clear();
        for(int n = 0; n < COGCODESIZE; n++) {
            //if(n < 16) qDebug("reg[%d] %08X", n, codep[n]);
            coginfo[num].codeList.append(cogmem[num][n]);
        }
        emit addCogInstructions(num,coginfo[num].codeList);
        QApplication::processEvents();
    }
}

int32  P8x32a::msTime()
{
    int32 millis = 0;
#if 1
    millis = QDateTime::currentMSecsSinceEpoch();
#else
    QTime time = QTime::currentTime();
    millis = millis + time.second();
    millis = millis + time.minute() * 60;
    millis = millis + time.hour() * 3600;
    millis = millis * 1000 + time.msec();
#endif
    return millis;
}

int32  P8x32a::getCount()
{
    int32 syscnt = loopcount;
    if(!debugCycleMode) {
#if 1
        int32  clkfreq = (*(int32*)&memory[0]);
        qint64 millis  = QDateTime::currentMSecsSinceEpoch();
        millis *= clkfreq/1000;
#else
        int32  clkfreq = (*(int32*)&memory[0])/1000;
        int32  ms = msTime();
        int32  millis = ms;
        millis *= clkfreq;
#endif
        syscnt = (int32) millis & 0xffffffff; // millis * ticks/ms = CNT
        //qDebug() << "getCount()" << millis << syscnt;
        return syscnt;
    }
    return syscnt;
}

void P8x32a::setDebugCycleMode(bool enable)
{
    debugCycleMode = enable;
}

void P8x32a::run()
{
    debugCycleMode = false;
    for(int n = 0; n < COGCOUNT; n++) {
        loopcount++;
        if(cogrun[n]) {
            execute(n, false);
        }
    }
}

void P8x32a::execute()
{
    debugCycleMode = true;
    for(int n = 0; n < COGCOUNT; n++) {
        loopcount++;
        if(cogrun[n]) {
            if(!passBreak && brkHash[QString("%1.%2").arg(n).arg(pc0[n])] != 0) {
                emit stopRunner();
                emit setCogPC(n, pc0[n]);
                emit showCogTab(n);
                passBreak = true;
                execute(n, true);
                return;
            }
            else {
                execute(n, true);
            }
            passBreak = false;
        }
    }
}

/*******************************************************************************
' execute() function:
' Original Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
/*******************************************************************************
' Mit license included here.
' Adapted by Steve Denson (C) 2014.
+--------------------------------------------------------------------
| TERMS OF USE: MIT License
+--------------------------------------------------------------------
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--------------------------------------------------------------------
'******************************************************************************/

int P8x32a::execute(int cog, bool debug)
{
    bool    simdebug = false;

    int     cpc = pc0[cog];
    uint32 *cogregs = (uint32*)&cogmem[cog];
    int32   result = 0;

    int32   tmp1  = 0;
    uint    dstsave = 0;
    uint    srcsave = 0;

    uint32 instruction = cogregs[cpc];

    uint32 opcode = (instruction & INS_MASK) >> INS_START;
    uint32 ins_opsect = opcode >> 3;

    uint ins_cnd = (instruction & COND_MASK)    >> COND_START;
    uint ins_zcri= (instruction & ZCRI_MASK)    >> ZCRI_START;
    uint ins_wz  = ((instruction & ZCRI_WZ)     >> (ZCRI_START +3)) & 1;
    uint ins_wc  = ((instruction & ZCRI_WC)     >> (ZCRI_START +2)) & 1;
    uint ins_wr  = ((instruction & ZCRI_WR)     >> (ZCRI_START +1)) & 1;
    uint ins_imm = ((instruction & ZCRI_IMMED)  >> (ZCRI_START +0)) & 1;
    uint ins_src = (instruction & SRC_MASK)     >> SRC_START;
    uint ins_dst = (instruction & DST_MASK)     >> DST_START;

    cogregs[REG_CNT] = getCount();

    //if(ins_src == REG_CNT) { qDebug() << "instruction" << getInstName(opcode, ins_zcri, ins_cnd, ins_src) << cpc << "Get Count" << cogregs[REG_CNT]; }
    //else qDebug() << "instruction" << getInstName(opcode, ins_zcri, ins_cnd, ins_dst, ins_src) << cpc;

    int32 r_dst = cogregs[ins_dst];
    int32 r_src = ins_src;

    if(ins_imm)
        r_src = ins_src;
    else if(ins_src == REG_CNT)
        r_src = cogregs[REG_CNT];
    else if(ins_src == REG_INA)
        r_src = getPins(cog);
    else
        r_src = cogregs[ins_src];

    //debug = true; // temporary

    if(debug) {
        coginfo[cog].pc = cpc;
        coginfo[cog].ins = instruction;
        coginfo[cog].cond = ins_cnd;
        coginfo[cog].z = cog_zflag[cog];
        coginfo[cog].c = cog_cflag[cog];
        coginfo[cog].wr = ins_wr != 0;
        coginfo[cog].src = ins_src;
        coginfo[cog].dst = ins_dst;
        coginfo[cog].srcval = r_src;
        coginfo[cog].dstval = r_dst;
        emit setCogPC(cog,cpc);
    }

    int spinVarBase = cogregs[0x1ec] & (MEMSIZE-1);
    int spinStkBase = cogregs[0x1ed] & (MEMSIZE-1);
    int spinPcCurr  = cogregs[0x1ee] & (MEMSIZE-1);
    int spinObjPtr  = cogregs[0x1ef] & (MEMSIZE-1);

    int32 zflag = cog_zflag[cog];
    int32 cflag = cog_cflag[cog];

    if ((!( (ins_cnd >> ((cog_cflag[cog]<<1)|cog_zflag[cog])) & 1)) || (cpc&~REG_MASK)) {
        // Fetch instruction
        if(!waitflag[cog]) {
            pc0[cog] = (pc0[cog] + 1) & REG_MASK;
        }
        emit setCogPC(cog,cpc);
        return 0;
    }

    if(debugCycleMode && !(instruction & 0xe0000000)) {
        if(waitflag[cog]) {
            waitflag[cog]--;
        }
        else if(false) { // skip for now
            waitflag[cog] = ((cog >> 1) - loopcount) & 3;
            waitflag[cog]++;
        }
        //qDebug() << "WAIT" << waitflag[cog] << "OPCODE" << opcode << "CNT" << cogregs[REG_CNT];
        if(waitflag[cog]) {
            return 0;
        }
    }

    // once the first instruction is shown, mark as started and return.
    if(!cogstarted[cog]) {
        cogstarted[cog] = true;
        return 0;
    }

    if(pc0[cog] & DELAYSLOT_MASK) { // djnz, tjz, tjnz delay slot
        pc0[cog] &= ~DELAYSLOT_MASK;
        pc0[cog] = (pc0[cog] + 1) & REG_MASK;
        return 0;
    }

    switch(ins_opsect) {
        case 0: // hubops, etc....
            switch(opcode & 7) {
                case 0  :     // hub access byte ... rdbyte or write byte depending upon r state
                case 1  :
                case 2  :
                    if(((uint)r_src) > MEMSIZE) {
                        //qDebug() << QString("HUBRAM Address out of range: %1").arg(r_src,8,16,QChar(QLatin1Char('0')));
                        r_src &= (MEMSIZE-1);
                    }

                    if(ins_wr) {    // read hub ram
                        if((opcode & 7) == 0) {
                            result = *((uchar*) &memory[r_src]);
                        } else if((opcode & 7) == 1) {
                            result = *((ushort*)&memory[r_src]);
                        } else if((opcode & 7) == 2) {
                            result = *((uint32*)&memory[r_src]);
                        }
                        zflag = !result ? 1 : 0;
                    }
                    else {          // write hub ram
                        if((opcode & 7) == 0) {
                            *((uchar*)  &memory[r_src]) = (uchar)  r_dst;
                            if(debug) emit pokeHubMem(r_src, r_dst, 1);
                        } else if((opcode & 7) == 1) {
                            *((ushort*) &memory[r_src]) = (ushort) r_dst;
                            if(debug) emit pokeHubMem(r_src, r_dst, 2);
                        } else if((opcode & 7) == 2) {
                            *((uint32*) &memory[r_src]) = (uint32) r_dst;
                            if(debug) emit pokeHubMem(r_src, r_dst, 4);
                        }
                    }

                    if(simdebug) {
                        if(r_src >= spinVarBase && r_src < spinStkBase) {
                            if(!ins_wr)
                                qDebug() << "COG" << cog << QString("VAR Write %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(r_dst&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                            else
                                qDebug() << "COG" << cog << QString("VAR Read  %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(result&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                        }
                        else if(r_src >= (int)cogregs[spinObjPtr+16] && r_src < spinPcCurr) {
                            if(!ins_wr)
                                qDebug() << "COG" << cog << QString("DAT Write %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(r_dst&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                            else
                                qDebug() << "COG" << cog << QString("DAT Read  %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(result&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                        }
                        else if(r_src == spinPcCurr) {
                            if(!ins_wr)
                                qDebug() << "COG" << cog << QString("PC  Write %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(r_dst&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                            else
                                qDebug() << "COG" << cog << QString("PC  Read  %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(result&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                        }
                        else if(r_src > spinStkBase) {
                            if(!ins_wr)
                                qDebug() << "COG" << cog << QString("Mem Write %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(r_dst&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                            else
                                qDebug() << "COG" << cog << QString("Mem Read  %1 %2").arg(r_src,3,16,QChar(QLatin1Char('0'))).arg(result&0xffffffff,(opcode&7)*2,16,QChar(QLatin1Char('0')));
                        }
                    }

                break;
                case 3   :     // multiple meaning depending upon zcri and src bits
                    switch(r_src & 7) {
                        uint par, addr;
                        case 0: // clkset
                            result = r_dst & 0xff;
                            if (result & 0x80)
                            {
                                initialize();
                                boot();
                                return 0;
                            }
                            break;
                        case 1: // cogid
                            result = cog;
                            break;

                        case 2: // coginit
                            par  = (r_dst >> 16) & 0xfffc;
                            addr = (r_dst >> 2) & 0xfffc;
                            if (r_dst & 8) {// Start new cog
                                result = coginit((uint32*)&memory[addr],par,0,1);
                                if (result == 8) { // Check if none available
                                    cflag = 1;
                                    result = 7;
                                    zflag = 0;
                                    break;
                                }
                            }
                            else {
                                result = coginit((uint32*)&memory[addr],par,r_dst&7,0);
                            }
                            cflag = 0;
                            zflag = (result == 0);
                            if(debug) // dont trace during run. breaks some code
                                traceEdit.appendPlainText(
                                    QString("%1 ").arg(loopcount,10,10)+
                                    QString("COG %1 ").arg(cog,1,10)+
                                    QString("PC %1 ").arg(cpc,3,16,QChar(QLatin1Char('0')))+
                                    QString(" %1 ").arg(instruction,8,16,QChar(QLatin1Char('0')))+
                                    QString("%1").arg(getCondition(ins_cnd),12)+
                                    QString(" %1").arg(getInstName(opcode, ins_zcri, ins_cnd, ins_src),8)+
                                    " WC "+(ins_wc?"1":"0")+
                                    " WZ "+(ins_wz?"1":"0")+
                                    " WR "+(ins_wr?"1":"0")+
                                    QString(" DST %1 ").arg(ins_dst,3,16,QChar(QLatin1Char('0')))+
                                    QString("%1 ").arg(dstsave,8,16,QChar(QLatin1Char('0')))+
                                    "SRC "+(ins_imm?"#":" ")+
                                    QString("$%1 ").arg(ins_src,3,16,QChar(QLatin1Char('0')))+
                                    (ins_imm?"         ":QString("%1 ").arg(srcsave,8,16,QChar(QLatin1Char('0'))))+
                                    "C "+(cflag?"1":"0")+" Z "+(zflag?"1":"0")+
                                    QString(" RESULT $%1").arg((ins_wr==0)?0:(uint)result,3,16,QChar(QLatin1Char('0'))));
                            return result;
                        break;

                        case 3: // cogstop
                            for(result = 0; result < COGCOUNT; result++)
                                if(cogrun[result]) break;
                            cflag = (result == 8);
                            result = r_dst & 7;
                            cogrun[result] = false;
                            zflag = (result == 0);
                            //return result;
                        break;

                        case 4: // locknew
                            for(result = 0; result < COGCOUNT; result++)
                                if (!lockalloc[result]) break;
                            if (result == 8) {
                                cflag = 1;
                                result = 7;
                            }
                            else {
                                cflag = 0;
                                lockalloc[result] = true;
                            }
                            zflag = (result == 0);
                        break;

                        case 5: // lockret
                            for(result = 0; result < COGCOUNT; result++)
                                if(!lockalloc[result]) break;
                            cflag = (result == 8);
                            result = r_dst & 7;
                            zflag = (result == 0);
                            lockalloc[result] = false;
                        break;

                        case 6: // lockset
                            result = r_dst & 7;
                            zflag = (result == 0);
                            cflag = locks[result] ? 1:0;
                            locks[result] = true;
                        break;

                        case 7: // lockclr
                            result = r_dst & 7;
                            zflag = (result == 0);
                            cflag = locks[result] ? 1:0;
                            locks[result] = false;
                        break;
                    }
                break;
                default:
                    qDebug() << "Unknown opcode" << opcode;
                    break;
            }
            break;

            // Rotate and shift
            case 1:
            r_src &= 0x1f; // Get five LSB's
            switch (opcode & 7)
            {
                case 0: // ror
                result = (((uint32)r_dst) >> r_src) | (r_dst << (32 - r_src));
                cflag = r_dst & 1;
                break;

                case 1: // rol
                result = (((uint32)r_dst) >> (32 - r_src)) | (r_dst << r_src);
                cflag = (r_dst >> 31) & 1;
                break;

                case 2: // shr
                result = (((uint32)r_dst) >> r_src);
                cflag = r_dst & 1;
                break;

                case 3: // shl
                result = (r_dst << r_src);
                cflag = (r_dst >> 31) & 1;
                break;

                case 4: // rcr
                if (r_src)
                {
                    result = (cflag << 31) | (((uint32)r_dst) >> 1);
                    result >>= (r_src - 1);
                }
                else
                    result = r_dst;
                cflag = r_dst & 1;
                break;

                case 5: // rcl
                result = cflag ? (1 << r_src) - 1 : 0;
                result |= (r_dst << r_src);
                cflag = (r_dst >> 31) & 1;
                break;

                case 6: // sar
                result = r_dst >> r_src;
                cflag = r_dst & 1;
                break;

                case 7: // rev
                cflag = r_dst & 1;
                r_src = 32 - r_src;
                result = 0;
                while (r_src-- > 0)
                {
                    result = (result << 1) | (r_dst & 1);
                    r_dst >>= 1;
                }
                break;
            }
            zflag = (result == 0);
            break;

            // Jump, call, return and misc.
            case 2:
            switch (opcode & 7)
            {
                case 0: // mins
                cflag = (r_dst < r_src);
                zflag = (r_src == 0);
                result = cflag ? r_src : r_dst;
                break;

                case 1: // maxs
                cflag = (r_dst < r_src);
                zflag = (r_src == 0);
                result = cflag ? r_dst : r_src;
                break;

                case 2: // min
                cflag = (((uint32)r_dst) < ((uint32)r_src));
                zflag = (r_src == 0);
                result = cflag ? r_src : r_dst;
                break;

                case 3: // max
                cflag = (((uint32)r_dst) < ((uint32)r_src));
                zflag = (r_src == 0);
                result = cflag ? r_dst : r_src;
                break;

                case 4: // movs
                cflag = ((uint32)r_dst) < ((uint32)r_src);
                result = (r_dst & 0xfffffe00) | (r_src &REG_MASK);
                zflag = (result == 0);
                break;

                case 5: // movd
                cflag = ((uint32)r_dst) < ((uint32)r_src);
                result = (r_dst & 0xfffc01ff) | ((r_src &REG_MASK) << 9);
                zflag = (result == 0);
                break;

                case 6: // movi
                cflag = ((uint32)r_dst) < ((uint32)r_src);
                result = (r_dst & 0x007fffff) | ((r_src &REG_MASK) << 23);
                zflag = (result == 0);
                break;

                case 7: // ret, jmp, call, jmpret
                cflag = ((uint32)r_dst) < ((uint32)r_src);
                result = (r_dst & 0xfffffe00) | ((cpc + 1) & REG_MASK);
                zflag = (result == 0);
                pc0[cog] = (r_src & REG_MASK) | JUMPINSTR_MASK;
                break;
            }
            break;

            // Logical operations
            case 3:
            switch (opcode & 7)
            {
                case 0: // test, and
                result = r_dst & r_src;
                break;

                case 1: // testn, andn
                result = r_dst & (~r_src);
                break;

                case 2: // or
                result = r_dst | r_src;
                break;

                case 3: // xor
                result = r_dst ^ r_src;
                break;

                case 4: // muxc
                result = (r_dst & (~r_src)) | (r_src & (-cflag));
                break;

                case 5: // muxnc
                result = (r_dst & (~r_src)) | (r_src & (~(-cflag)));
                break;

                case 6: // muxz
                result = (r_dst & (~r_src)) | (r_src & (-zflag));
                break;

                case 7: // muxnz
                result = (r_dst & (~r_src)) | (r_src & (~(-zflag)));
                break;
            }
            zflag = (result == 0);
            cflag = parity((uint32)result);
            break;

            // Add and subtract
            case 4:
            switch (opcode & 7)
            {
                case 0: // add
                result = r_dst + r_src;
                cflag = (((r_dst & r_src) | ((r_dst | r_src) & (~result))) >> 31) & 1;
                break;

                case 1: // cmp, sub
                result = r_dst - r_src;
                cflag = ((uint32)r_dst) < ((uint32)r_src);
                break;

                case 2: // addabs
                cflag = (r_src >> 31) & 1;
                r_src = abs(r_src);
                result = r_dst + r_src;
                cflag ^= (((r_dst & r_src) | ((r_dst | r_src) & (~result))) >> 31) & 1;
                break;

                case 3: // subabs
                result = abs(r_src);
                cflag = ((r_src >> 31) & 1) ^
                    (((uint32)r_dst) < ((uint32)result));
                result = r_dst - result;
                break;

                case 4: // sumc
                result = cflag ? r_dst - r_src : r_dst + r_src;
                cflag = (~cflag) << 31;
                cflag = (((cflag ^ r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                break;

                case 5: // sumnc
                result = cflag ? r_dst + r_src : r_dst - r_src;
                cflag = cflag << 31;
                cflag = (((cflag ^ r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                break;

                case 6: // sumz
                result = zflag ? r_dst - r_src : r_dst + r_src;
                cflag = (~zflag) << 31;
                cflag = (((cflag ^ r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                break;

                case 7: // sumnz
                result = zflag ? r_dst + r_src : r_dst - r_src;
                cflag = zflag << 31;
                cflag = (((cflag ^ r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                break;
            }
            zflag = (result == 0);
            break;

            // Move, absolute and negate
            case 5:
            switch (opcode & 7)
            {
                case 0: // mov
                result = r_src;
                cflag = (r_src >> 31) & 1;
                break;

                case 1: // neg
                cflag = r_src < 0;
                result = -r_src;
                break;

                case 2: // abs
                cflag = (r_src >> 31) & 1;
                result = abs(r_src);
                break;

                case 3: // absneg
                cflag = (r_src >> 31) & 1;
                result = -abs(r_src);
                break;

                case 4: // negc
                result = cflag ? -r_src : r_src;
                cflag = (r_src >> 31) & 1;
                break;

                case 5: // negnc
                result = cflag ? r_src : -r_src;
                cflag = (r_src >> 31) & 1;
                break;

                case 6: // negz
                result = zflag ? -r_src : r_src;
                cflag = (r_src >> 31) & 1;
                break;

                case 7: // negnz
                result = zflag ? r_src : -r_src;
                cflag = (r_src >> 31) & 1;
                break;
            }
            zflag = (result == 0);
            break;

            // More add and subtract
            case 6:
            switch (opcode & 7)
            {
                case 0: // cmps
                result = r_dst - r_src;
                cflag = r_dst < r_src;
                zflag = (result == 0);
                break;

                case 1: // cmpsx
                result = r_dst - r_src - cflag;
                cflag = r_dst < (r_src + cflag);
                zflag = (result == 0) & zflag;
                break;

                case 2: // addx
                result = r_dst + r_src + cflag;
                cflag = (((r_dst & r_src) | ((r_dst | r_src) & (~result))) >> 31) & 1;
                zflag = (result == 0) & zflag;
                break;

                case 3: // cmpx, subx
                result = r_dst - r_src - cflag;
                if (r_src != (int)0xffffffff || !cflag)
                    cflag = ((uint32)r_dst) < ((uint32)(r_src + cflag));
                zflag = (result == 0) & zflag;
                break;

                case 4: // adds
                result = r_dst + r_src;
                cflag = (((~(r_dst ^ r_src)) & (r_dst ^ result)) >> 31) & 1;
                zflag = (result == 0);
                break;

                case 5: // subs
                result = r_dst - r_src;
                zflag = (result == 0);
                cflag = (((r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                break;

                case 6: // addsx
                result = r_dst + r_src + cflag;
                cflag = (((~(r_dst ^ r_src)) & (r_dst ^ result)) >> 31) & 1;
                zflag = (result == 0) & zflag;
                break;

                case 7: // subsx
                result = r_dst - r_src - cflag;
                cflag = (((r_dst ^ r_src) & (r_dst ^ result)) >> 31) & 1;
                zflag = (result == 0) & zflag;
                break;
            }
            break;

            // Test and jump and wait ops
            case 7:
            switch (opcode & 7)
            {
                case 0: // cmpsub
                cflag = (((uint32)r_dst) >= ((uint32)r_src));
                result = cflag ? r_dst - r_src : r_dst;
                zflag = (result == 0);
                break;

                case 1: // djnz
                result = r_dst - 1;
                zflag = (result == 0);
                //cflag = (result == -1);
                cflag = (result < 0);
                if(!zflag) {
                    pc0[cog] = (r_src & REG_MASK) | JUMPINSTR_MASK;
                } else {
                    pc0[cog] |= DELAYSLOT_MASK;
                }
                break;

                case 2: // tjnz
                result = r_dst;
                zflag = (result == 0);
                cflag = 0;
                if(!zflag) {
                    pc0[cog] = (r_src & REG_MASK) | JUMPINSTR_MASK;
                } else {
                    pc0[cog] |= DELAYSLOT_MASK;
                }
                break;

                case 3: // tjz
                result = r_dst;
                zflag = (result == 0);
                cflag = 0;
                if(zflag) {
                    pc0[cog] = (r_src & REG_MASK) | JUMPINSTR_MASK;
                } else {
                    pc0[cog] |= DELAYSLOT_MASK;
                }

                break;

                case 4: // waitpeq - result, zflag and cflag not validated
                tmp1 = getPins(cog);
                result = (tmp1 & r_src);
                //qDebug() << "waitpeq" << QString("%1").arg(r_dst,8,16) << QString("%1").arg(tmp1,8,16);
                if (result != r_src)
                {
                    return 0;
                }
                else
                {
                    waitflag[cog] = 0;
                    zflag = (result == 0);
                    cflag = 0;
                }
                break;

                case 5: // waitpne - result, zflag and cflag not validated
                tmp1 = getPins(cog);
                result = (tmp1 & r_src);
                //qDebug() << "waitpne" << QString("%1").arg(r_dst,8,16) << QString("%1").arg(tmp1,8,16);
                if (result == r_src)
                {
                    return 0;
                }
                else
                {
                    waitflag[cog] = 0;
                    zflag = (result == 0);
                    cflag = zflag;
                }
                break;

                case 6: // waitcnt
                    tmp1 = cogregs[REG_CNT];
                    result = tmp1 - r_dst;
                    // qDebug() << "waitcnt" << result << "=" << tmp1 << "-" << r_dst << "next" << r_dst + r_src;
                    if(result < 0) {
                        result = r_dst;
                        waitflag[cog] = 1;
                        if(debugCycleMode) {
                            /* Looping until good would be nice, but we lose control of the GUI. Don't do it.
                                while(getCount() - r_dst) loopcount++;
                            */
                            loopcount = r_dst;
                            waitflag[cog] = 0;
                            result = r_dst + r_src;
                            zflag = (result == 0);
                            cflag = (((r_dst & r_src) | ((r_dst | r_src) & (~result))) >> 31) & 1;
                        }
                    }
                    else {
                        loopcount = r_dst;
                        waitflag[cog] = 0;
                        result = r_dst + r_src;
                        zflag = (result == 0);
                        cflag = (((r_dst & r_src) | ((r_dst | r_src) & (~result))) >> 31) & 1;
                    }
                break;

                case 7: // waitvid
                break;
            }
            break;
    }

    dstsave = cogregs[ins_dst];
    srcsave = cogregs[ins_src];

    // Conditionally update flags and write result
    if (ins_wz)
        cog_zflag[cog] = zflag;
    if (ins_wc)
        cog_cflag[cog] = cflag;
    if (ins_wr) {
        cogregs[ins_dst] = result;
        // Check if we need to update the pins
        if(ins_dst == REG_DIRA)
            setPinDir(cog,result);
        if(ins_dst == REG_OUTA)
            setPins(cog,result);
    }

    if(printinst) {
        qDebug("COG[%d] PC %3d INST %08X Z %d C %d S %03X D %03X R %08X",
               cog, cpc, instruction, cog_zflag[cog], cog_cflag[cog], ins_src, ins_dst, result);
        //qDebug() << "COG" << cog << "PC" << cpc << opcode << "ZCRI" << ins_zcri << "Z" << zflag[cog] << "C" << cflag[cog] << "RESULT" << result;
    }

    if(debug) {
        coginfo[cog].result = result;
        coginfo[cog].PAR = cogregs[REG_PAR];
        coginfo[cog].CNT = cogregs[REG_CNT];
        coginfo[cog].INA = getPins(cog);
        coginfo[cog].INB = cogregs[REG_INB];
        coginfo[cog].OUTA = cogregs[REG_OUTA];
        coginfo[cog].OUTB = cogregs[REG_OUTB];
        coginfo[cog].DIRA = cogregs[REG_DIRA];
        coginfo[cog].DIRB = cogregs[REG_DIRB];
        coginfo[cog].CTRA = cogregs[REG_CTRA];
        coginfo[cog].CTRB = cogregs[REG_CTRB];
        coginfo[cog].FRQA = cogregs[REG_FRQA];
        coginfo[cog].FRQB = cogregs[REG_FRQB];
        coginfo[cog].PHSA = cogregs[REG_PHSA];
        coginfo[cog].PHSB = cogregs[REG_PHSB];
        coginfo[cog].VCFG = cogregs[REG_VCFG];
        coginfo[cog].VSCL = cogregs[REG_VSCL];

        if(ins_wr != 0) {
            coginfo[cog].codeList.removeAt(ins_dst);
            coginfo[cog].codeList.insert(ins_dst,result);
        }
        emit showCog(cog, &coginfo[cog]);

        if(traceon) {  // dont trace during run. breaks some code
            bool isbytecode = false;
            bool iscmmcode  = false;
            if((cogregs[0x009] == 0x00bc0bee || cogregs[0x1ce] == 0x00bc0bde) && (cpc == 0x009 || cpc == 0x1ce))
                isbytecode = true;
            if(!isbytecode && cogregs[0x019] == 0x00bc2a11 && cpc == 0x019)
                iscmmcode  = true;

            traceEdit.appendPlainText(
                        QString("%1 ").arg(loopcount,10,10)+
                        QString("COG %1 ").arg(cog,1,10)+
                        QString("PC %1 ").arg(cpc,3,16,QChar(QLatin1Char('0')))+
                        QString(" %1 ").arg(instruction,8,16,QChar(QLatin1Char('0')))+
                        QString("%1").arg(getCondition(ins_cnd),12)+
                        QString(" %1").arg(getInstName(opcode, ins_zcri, ins_cnd, ins_src),8)+
                        " WC "+(ins_wc?"1":"0")+
                        " WZ "+(ins_wz?"1":"0")+
                        " WR "+(ins_wr?"1":"0")+
                        QString(" DST %1 ").arg(ins_dst,3,16,QChar(QLatin1Char('0')))+
                        QString("%1 ").arg(dstsave,8,16,QChar(QLatin1Char('0')))+
                        "SRC "+(ins_imm?"#":" ")+
                        QString("$%1 ").arg(ins_src,3,16,QChar(QLatin1Char('0')))+
                        (ins_imm?"         ":QString("%1 ").arg(srcsave,8,16,QChar(QLatin1Char('0'))))+
                        "C "+(cflag?"1":"0")+" Z "+(zflag?"1":"0")+
                        QString(" RESULT $%1").arg((ins_wr==0)?0:(uint)result,3,16,QChar(QLatin1Char('0')))+
                        QString("%1").arg(isbytecode?" <<SPIN>>":(iscmmcode?" <<CMM>>":"")));
        }
    }

    // Fetch instruction
    if(!waitflag[cog]) {
        // if not same we had a jmp
        if(cpc == pc0[cog])
            pc0[cog] = (pc0[cog] + 1) & REG_MASK;
        // instruction line jmp #$
        else if(pc0[cog] & JUMPINSTR_MASK)
            pc0[cog] &= ~JUMPINSTR_MASK;
    }

    return result;
}

void P8x32a::highlightCurrentLine(QPlainTextEdit *ed, QColor lineColor)
{
    if(lineColor.isValid() == false) {
        lineColor.setRgb(255,255,255);
    }
    // for gdb use: QColor lineColor = QColor(Qt::yellow).lighter(160);
    QList<QTextEdit::ExtraSelection> extraSelections;

    if (true) {
        QTextEdit::ExtraSelection selection;

        selection.format.setBackground(lineColor);
        selection.format.setProperty(QTextFormat::FullWidthSelection, true);
        selection.format.setProperty(QTextFormat::UserProperty + 1, 1);
        selection.cursor = ed->textCursor();
        selection.cursor.clearSelection();
        extraSelections.append(selection);
    }

    ed->setExtraSelections(extraSelections);
}

#if 0
#include <QTextBlock>

void P8x32a::updateBackgroundColors()
{
    QList<QTextEdit::ExtraSelection> OurExtraSelections;

    QTextEdit::ExtraSelection selection;

    selection.format.setBackground(QColor(Qt::white));
    selection.format.setProperty(QTextFormat::FullWidthSelection, true);
    selection.format.setProperty(QTextFormat::UserProperty + 1, 1); // mark it as a highlightCurrentLine format
    selection.cursor = traceEdit.textCursor();
    selection.cursor.clearSelection();
    selection.cursor.movePosition(QTextCursor::Start);

    QTextBlock currBlock = traceEdit.document()->firstBlock();
    while (1)
    {
        if(currBlock.text().contains("COG 0") &&
           currBlock.text().contains("PC 009") &&
           currBlock.text().contains("00bc0bee")) {
            OurExtraSelections.append(selection);
            selection.format.setBackground(QColor(167,210,253));
        }
        else {
            OurExtraSelections.append(selection);
            selection.format.setBackground(QColor(Qt::white));
        }
        selection.cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
        selection.cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor);

        if (currBlock == traceEdit.document()->lastBlock()) {
            break;
        }

        currBlock = currBlock.next();
    }

    selection.cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
    OurExtraSelections.append(selection);

    traceEdit.setExtraSelections(OurExtraSelections);
}
#endif

QString P8x32a::getInstName(int opcode, int zcri, int cond, int src)
{
    if(!cond)
        return QString("");

    switch(opcode << INS_START) {

        case INS_HABYTE  :
            if(zcri & 2)
                return QString("RDBYTE");
            else
                return QString("WRBYTE");
            break;
        case INS_HAWORD  :
            if(zcri & 2)
                return QString("RDWORD");
            else
                return QString("WRWORD");
            break;
        case INS_HALONG  :
            if(zcri & 2)
                return QString("RDLONG");
            else
                return QString("WRLONG");
            break;
        case INS_HUBOP   :
            switch(src) {
                case 0: return QString("CLKSET");
                    break;
                case 1: return QString("COGID");
                    break;
                case 2: return QString("COGINIT");
                    break;
                case 3: return QString("COGSTOP");
                    break;
                case 4: return QString("LOCKNEW");
                    break;
                case 5: return QString("LOCKRET");
                    break;
                case 6: return QString("LOCKSET");
                    break;
                case 7: return QString("LOCKCLR");
                    break;
                default:
                    break;
            }
        break;
        case INS_MUL     : return QString("MUL N/A");
        break;
        case INS_MULS    : return QString("MULS N/A");
        break;
        case INS_ENC     : return QString("ENC N/A");
        break;
        case INS_ONES    : return QString("ONES N/A");
        break;
        case INS_ROR     : return QString("ROR");
        break;
        case INS_ROL     : return QString("ROL");
        break;
        case INS_SHR     : return QString("SHR");
        break;
        case INS_SHL     : return QString("SHL");
        break;
        case INS_RCR     : return QString("RCR");
        break;
        case INS_RCL     : return QString("RCL");
        break;
        case INS_SAR     : return QString("SAR");
        break;
        case INS_REV     : return QString("REV");
        break;
        case INS_MINS    : return QString("MINS");
        break;
        case INS_MAXS    : return QString("MAXS");
        break;
        case INS_MIN     : return QString("MIN");
        break;
        case INS_MAX     : return QString("MAX");
        break;
        case INS_MOVS    : return QString("MOVS");
        break;
        case INS_MOVD    : return QString("MOVD");
        break;
        case INS_MOVI    : return QString("MOVI");
        break;
        case INS_JMP     : {
            int jtype = zcri & 3;
            if(jtype == 3)
                return QString("CALL");
            else if(jtype == 2)
                return QString("JMPRET");
            else if(jtype == 1)
                return QString("JMP");
            else if(jtype == 0)
                return QString("RET");
        }
        break;
        case INS_AND     :
            if(!(zcri & 2))
                return QString("TEST");
            else
                return QString("AND");
        break;
        case INS_ANDN    :
            if(!(zcri & 2))
                return QString("TESTN");
            else
                return QString("ANDN");
        break;
        case INS_OR      : return QString("OR");
        break;
        case INS_XOR     : return QString("XOR");
        break;
        case INS_MUXC    : return QString("MUXC");
        break;
        case INS_MUXNC   : return QString("MUXNC");
        break;
        case INS_MUXZ    : return QString("MUXZ");
        break;
        case INS_MUXNZ   : return QString("MUXNZ");
        break;
        case INS_ADD     : return QString("ADD");
        break;
        case INS_SUB     :
            if(zcri & 2)
                return QString("SUB");
            else
                return QString("CMP");
        break;
        case INS_ADDABS  : return QString("ADDABS");
        break;
        case INS_SUBABS  : return QString("SUBABS");
        break;
        case INS_SUMC    : return QString("SUMC");
        break;
        case INS_SUMNC   : return QString("SUMNC");
        break;
        case INS_SUMZ    : return QString("SUMZ");
        break;
        case INS_SUMNZ   : return QString("SUMNZ");
        break;
        case INS_MOV     : return QString("MOV");
        break;
        case INS_NEG     : return QString("NEG");
        break;
        case INS_ABS     : return QString("ABS");
        break;
        case INS_ABSNEG  : return QString("ABSNEG");
        break;
        case INS_NEGC    : return QString("NEGC");
        break;
        case INS_NEGNC   : return QString("NEGNC");
        break;
        case INS_NEGZ    : return QString("NEGZ");
        break;
        case INS_NEGNZ   : return QString("NEGNZ");
        break;
        case INS_CMPS    : return QString("CMPS");
        break;
        case INS_CMPSX   : return QString("CMPSX");
        break;
        case INS_ADDX    : return QString("ADDX");
        break;
        case INS_SUBX    :
            if(zcri & 2)
                return QString("SUBX");
            else
                return QString("CMPX");
        break;
        case INS_ADDS    : return QString("ADDS");
        break;
        case INS_SUBS    : return QString("SUBS");
        break;
        case INS_ADDSX   : return QString("ADDSX");
        break;
        case INS_SUBSX   : return QString("SUBSX");
        break;
        case INS_CMPSUB  : return QString("CMPSUB");
        break;
        case INS_DJNZ    : return QString("DJNZ");
        break;
        case INS_TJNZ    : return QString("TJNZ");
        break;
        case INS_TJZ     : return QString("TJZ");
        break;
        case INS_WAITPEQ : return QString("WAITPEQ");
        break;
        case INS_WAITPNE : return QString("WAITPNE");
        break;
        case INS_WAITCNT : return QString("WAITCNT");
        break;
        case INS_WAITVID : return QString("WAITVID");
        break;
    }
    return QString();
}

QString P8x32a::getCondition(int opcond)
{
    switch(opcond) {
        case 0:
            return QString("NOP");
            break;
        case 1:
            return QString("if_nc_and_nz");
            break;
        case 2:
            return QString("if_nc_and_z");
            break;
        case 3:
            return QString("if_nc");
            break;
        case 4:
            return QString("if_c_and_nz");
            break;
        case 5:
            return QString("if_nz");
            break;
        case 6:
            return QString("if_c_ne_z");
            break;
        case 7:
            return QString("if_nc_or_nz");
            break;
        case 8:
            return QString("if_c_and_z");
            break;
        case 9:
            return QString("if_c_eq_z");
            break;
        case 10:
            return QString("if_z");
            break;
        case 11:
            return QString("if_nc_or_z");
            break;
        case 12:
            return QString("if_c");
            break;
        case 13:
            return QString("if_c_or_nz");
            break;
        case 14:
            return QString("if_c_or_z");
            break;
        case 15:
            return QString("");
            break;
        default:
            break;
    }
    return QString();
}

